#ifndef __THREAD_POOL__
#define __THREAD_POOL__

#include <iostream>
#include <thread>
#include <condition_variable>
#include <queue>
#include <atomic>
#include <functional>
#include <mutex>
#include <unistd.h>
#include <memory>
#include <unordered_map>
#include <future>

#define DEBUG 1

const int TASK_MAX_THRESHHOLD = 30;    // 任务队列上限阈值
const int THREAD_MAX_THRESHHOLD = 10; // 线程数量上限阈值
const int THREAD_MAX_IDLE_TIME = 10;  // 多久没有新任务,多余的线程被回收

class Thread
{

public:
    using Func_t = std::function<void(int)>;
    Thread(Func_t func) : _func(func), _threadId(_ThreadNum++)
    {
    }
    ~Thread() {}

    void start()
    {
        std::thread t(_func, _threadId);
        t.detach(); // 如果不设置为分离线程,出了start作用域即被析构
    }
    int GetThreadId() const
    {
        return _threadId;
    }

private:
    int _threadId;
    Func_t _func;
    static int _ThreadNum;
};

int Thread::_ThreadNum = 0;

enum class PoolMode
{
    MODE_FIXED,
    MODE_CACHED
};

class ThreadPool
{
public:
    ThreadPool() : initThreadSize_(4),
                   TaskSize_(0),
                   taskQueMaxThreadHold_(TASK_MAX_THRESHHOLD),
                   poolMode_(PoolMode::MODE_FIXED),
                   isPoolRunning_(false),
                   idleThreadSize_(0),
                   threadSizeThreshHold_(THREAD_MAX_THRESHHOLD),
                   curThreadSize_(0)
    {
    }

    ThreadPool(const ThreadPool &) = delete;
    ThreadPool &operator=(const ThreadPool &) = delete;

    ~ThreadPool()
    {
        isPoolRunning_ = false;
        std::unique_lock<std::mutex> lock(taskQueMtx_);
        //-------------------------------------
        // TODO ? 是否要唤醒全部线程
        //Anser: 一定要,问题答案在ThreadFun中
        notEmpty_.notify_all();
        //-------------------------------------
        exitCond_.wait(lock, [&]() -> bool
                       { return TaskSize_ == 0; });
        std::cout << "任务执行完毕,exit"<<std::endl;
    }

    bool setMode(PoolMode poolmode)
    {
        if (checkRunningState())
            return false;
        poolMode_ = poolmode;
        return true;
    }

    void setTaskQueMaxThreshHold(int threshHold)
    {
        taskQueMaxThreadHold_ = threshHold;
    }
    void start(int initThreadSize = std::thread::hardware_concurrency()) // 系统调用获取CUP数量
    {
        initThreadSize_ = initThreadSize;
        isPoolRunning_ = true;
        for (int i = 0; i < initThreadSize_; i++)
        {
            std::unique_ptr<Thread> thread = std::unique_ptr<Thread>(new Thread(std::bind(&ThreadPool::ThreadFunc, this, std::placeholders::_1)));
            int threadId = thread->GetThreadId();
            threads_.insert(std::make_pair(threadId, std::move(thread)));
            curThreadSize_++;
        }
        for (int i = 0; i < curThreadSize_; i++)
        {
            std::cout << "线程: " << i << "  start  " << std::endl;

            threads_[i]->start();
            idleThreadSize_++;
        }
    }

    template <class Func, class... Args>
    auto submitTask(Func &&func, Args &&...args) -> std::future<decltype(func(args...))>
    {
        using RType = decltype(func(args...));
        if (!isPoolRunning_)
            return (std::packaged_task<RType()>([]() -> RType
                                                { return RType(); }))
                .get_future();

        auto task = std::make_shared<std::packaged_task<RType()>>(std::bind(std::forward<Func>(func), std::forward<Args>(args)...));

        std::future<RType> result = task->get_future();

        std::unique_lock<std::mutex> lock(taskQueMtx_);
        if (!notFull_.wait_for(lock, std::chrono::seconds(1), [&]() -> bool
                               { return TaskQue_.size() < taskQueMaxThreadHold_; }))
        {
            std::cout << "submitask fail......" << std::endl;
            auto task = std::make_shared<std::packaged_task<RType()>>([]() -> RType
                                                                      { return RType(); });
            (*task)();
            return task->get_future();
        }

        TaskQue_.emplace([task]()
                         { (*task)(); });

        TaskSize_++;
        std::cout << "submit success: " << TaskQue_.size() << std::endl;

        notEmpty_.notify_all();

        if (PoolMode::MODE_CACHED == poolMode_ && idleThreadSize_ < TaskSize_ && curThreadSize_ < threadSizeThreshHold_)
        {
            Thread_Create_And_Start();
        }
        return result;
    };
    void setThreadSizeThreshHold(int threshhold) 
    {
        if (checkRunningState())
            return;
        if (poolMode_ == PoolMode::MODE_CACHED)
            threadSizeThreshHold_ = threshhold;
    }

private:
    void Thread_Create_And_Start()
    {
        std::unique_ptr<Thread> thread = std::unique_ptr<Thread>(new Thread(std::bind(&ThreadPool::ThreadFunc, this, std::placeholders::_1)));
        int threadId = thread->GetThreadId();
        threads_.insert(std::make_pair(threadId, std::move(thread)));
        curThreadSize_++;
        thread->start();
        idleThreadSize_++;
    }
    void ThreadFunc(int ThreadId)
    {
        auto lastTime = std::chrono::high_resolution_clock().now();
        for (;;)
        {
            Task task;
            {
                std::unique_lock<std::mutex> lock(taskQueMtx_);
                std::cout << "线程: " << ThreadId << " 开始获取任务" << std::endl;
                while (TaskSize_ == 0)
                {
                    if (!isPoolRunning_)
                    {
                        DeleteThread(ThreadId);
                        exitCond_.notify_all();
                        return;
                    }
                    if (poolMode_ == PoolMode::MODE_CACHED)
                    {
                        if (std::cv_status::timeout == notEmpty_.wait_for(lock, std::chrono::seconds(1)))
                        {
                            auto cur = std::chrono::high_resolution_clock().now();
                            auto dur = std::chrono::duration_cast<std::chrono::seconds>(cur - lastTime);
                            if (dur.count() >= THREAD_MAX_IDLE_TIME && curThreadSize_ > initThreadSize_)
                            {
                                DeleteThread(ThreadId);
                                exitCond_.notify_all();
                                return;
                            }
                        }
                    }
                    else
                    {
                        //关于析构时是否要唤醒全部线程的证据
                        //线程停留在此,析构时此线程一直被阻塞
                        //必须唤醒
                        notEmpty_.wait(lock);
                    }
                }
                task = TaskQue_.front();
                TaskSize_--;
                idleThreadSize_--;
                TaskQue_.pop();
                std::cout << "线程: " << ThreadId << " 获取任务成功" << std::endl;
            }

            task();
            idleThreadSize_++;
            lastTime = std::chrono::high_resolution_clock().now();
        }
    }
    bool checkRunningState() const
    {
        return isPoolRunning_;
    }

    void DeleteThread(int ThreadId)
    {
        threads_.erase(ThreadId);
        curThreadSize_--;
        idleThreadSize_--;
    }

private:
    std::unordered_map<int, std::unique_ptr<Thread>> threads_; // 线程列表
    PoolMode poolMode_;                                        // 线程池工作模式

    // std::vector<std::unique_ptr<Thread>> threads_; // 线程列表
    size_t initThreadSize_;          // 初始化线程数量
    int threadSizeThreshHold_;       // 线程上限数量
    std::atomic_int curThreadSize_;  // 当前线程数量
    std::atomic_int idleThreadSize_; // 记录当前空闲线程的数量

    using Task = std::function<void()>;
    std::queue<Task> TaskQue_;  // 任务队列
    std::atomic_uint TaskSize_; // 任务数量
    int taskQueMaxThreadHold_;  // 任务队列数量上线阈值

    std::mutex taskQueMtx_;            // 保证任务队列的线程安全
    std::condition_variable notFull_;  // 任务队列不空
    std::condition_variable notEmpty_; // 任务队列不满
    std::condition_variable exitCond_; // 等待线程资源全部回收

    std::atomic_bool isPoolRunning_; // 当前线程池的状态
};

#endif